#include "MySqlConnPool/include/sqlsetmanager.h"
std::string SqlSetManager::host=std::string();
std::string SqlSetManager::user=std::string();
std::string SqlSetManager::passwd=std::string();
int SqlSetManager::conf_min_num=0;
int SqlSetManager::conf_max_num=0;
int SqlSetManager::conf_free_time=0;
int SqlSetManager::conf_timeout=0;

SqlSetManager SqlSetManager::manager;

SqlSetManager::SqlSetManager()
{
    readConf();
    db_num=0;
    tail_set=nullptr;
    manager_thread=new std::thread([this] {
        monitorFunc(this); });
}


void SqlSetManager::readConf()
{
    std::ifstream conf_file;
    conf_file.open("./MySqlConnPool.conf",std::ios::in);
    if(!conf_file.is_open())
    {
        std::cout<<"open file failed"<<std::endl;
    }
    std::string line,content;
    while(conf_file>>line)
    {
        content.append(line);
    }

    rapidjson::Document doc;
    doc.Parse(content.c_str());
    host=doc["host"].GetString();
    user=doc["user"].GetString();
    passwd=doc["passwd"].GetString();
    conf_min_num=doc["min_conn_num"].GetInt();
    conf_max_num=doc["max_conn_num"].GetInt();
    conf_free_time=doc["free_time"].GetInt();

}

void SqlSetManager::createSet(SqlSetManager* obj,std::string db_name){
    //已存在该数据库
    if(obj->db_map.find(db_name)!=obj->db_map.end())
    {
        status_map.erase(db_name);
        return;
    }
    //新建集合
    SqlConnSet* conn_set=new SqlConnSet;
    conn_set->setDBname(db_name);
    tail_set=conn_set;
    //向集合中添加连接
    for(int i=0;i<conf_min_num;i++)
    {
        mysql* sql=new mysql();
        sql->connectToSql(host,user,passwd,db_name);
        conn_set->release(sql);
        conn_set->sizeUp();
    }
    std::cout<<"size -> "<<conn_set->getSize()<<"  av -> "<<conn_set->getAv()<<std::endl;
    db_map.insert({db_name,conn_set});
    status_map.at(db_name)=true;
    //添加到管理类维护
    conn_list.push_back(conn_set);
    std::cout<<"add db done  -> "<<db_name<<std::endl;
}

void SqlSetManager::monitorFunc(SqlSetManager *obj)
{
    std::list<SqlConnSet*>::iterator it;
    while(1)
    {
        for(SqlConnSet* cur_set:conn_list)
        {
            auto cur_time=std::chrono::high_resolution_clock::now();
            auto last_time=cur_set->getLastUseTime();
            auto free_time=std::chrono::duration_cast<std::chrono::milliseconds>(cur_time-last_time);
            int free_time_int=static_cast<int>(free_time.count());
            //std::cout<<cur_set->getAv()<<std::endl;
            if(free_time_int>=obj->conf_free_time
                    &&cur_set->getSize()>conf_min_num
                    &&cur_set->getAv()>2
                    )
            {
                for(int i=0;i<1;i++)
                {
                    auto dis_sql=cur_set->acquire();
                    dis_sql->disconnect();
                    cur_set->sizeDown();
                }
                std::cout<<cur_set->getDBname()<<"  size -> "<<cur_set->getSize()<<
                        "available -> "<<cur_set->getAv()<<std::endl;
            }
            else if(cur_set->getSize()<conf_max_num
                    &&cur_set->getAv()<2
                    )
            {
                for(int i=0;i<1;i++)
                {
                    mysql* new_sql=new mysql;
                    new_sql->connectToSql(host,user,passwd,cur_set->getDBname());
                    cur_set->release(new_sql);
                    cur_set->sizeUp();
                }
                std::cout<<cur_set->getDBname()<<"  size -> "<<cur_set->getSize()<<
                        "available -> "<<cur_set->getAv()<<std::endl;
            }
            else{
                continue;
            }
        }
    }
}

SqlSetManager *SqlSetManager::getInstance()
{
    return &manager;
}

void SqlSetManager::addNewDB(std::string dbname)
{
    //添加到准备表中
    status_map.insert({dbname,false});
    //创建新线程，在线程内创建
    std::thread t([this, dbname] {
        createSet(this, dbname); });
    //线程不堵塞
    t.detach();
}

//若数据库未就绪则会进入堵塞
SqlConnSet *SqlSetManager::getSet(const std::string &db_name)
{
    //不在数据库表中
    if(db_map.find(db_name)==db_map.end())
    {
        //不在准备表中
        if(status_map.find(db_name)==status_map.end())
        {
            return nullptr;
        }
    }
    //等待数据库集合就绪（堵塞）
    while(!status_map[db_name]){}
    return db_map[db_name];
}
